#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/of_gpio.h>

struct virtual_spi_master{
	struct spi_master *spi_master;
	struct work_struct work_queue;
};

static void spi_virtual_work(struct work_struct *work)
{
	unsigned long flags;
	struct spi_message *mesg;
	struct spi_transfer *xfer;
	struct spi_statistics *statm;
	struct spi_statistics *stats;
	struct virtual_spi_master *virtual_master = container_of(work, struct virtual_spi_master, work_queue);
	struct spi_master *master = virtual_master->spi_master;

	//获取自旋锁
	spin_lock_irqsave(&master->queue_lock, flags);
	while (!list_empty(&master->queue))
	{
		mesg = list_entry(master->queue.next, struct spi_message, queue);
		list_del_init(&mesg->queue);
		//暂时解锁
		spin_unlock_irqrestore(&master->queue_lock, flags);

		/* 模拟硬件传输一个spi_message */
		statm = &master->statistics;
		stats = &mesg->spi->statistics;
		//更新统计信息
		SPI_STATISTICS_INCREMENT_FIELD(statm, messages);
		SPI_STATISTICS_INCREMENT_FIELD(stats, messages);
		//依次传输 spi_transfer
		list_for_each_entry(xfer, &mesg->transfers, transfer_list)
		{
			//更新统计信息
			spi_statistics_add_transfer_stats(statm, xfer, master);
			spi_statistics_add_transfer_stats(stats, xfer, master);
			//传输
			if (xfer->tx_buf || xfer->rx_buf)
			{
				printk("transfer one\n");
			}
			else
			{
				if (xfer->len)
					printk("Bufferless transfer has length %u\n", xfer->len);
			}
		}

		//设置状态为0，表示传输成功
		mesg->status = 0;
		//执行传输完成回调
		if (mesg->complete)
			mesg->complete(mesg->context);

		//重新加锁
		spin_lock_irqsave(&master->queue_lock, flags);
	}

	//完成后解锁
	spin_unlock_irqrestore(&master->queue_lock, flags);
}

static int spi_virtual_setup(struct spi_device *spi_dev)
{
	//若采用的传统GPIO模式还需要在驱动中将gpio设置为输出
	if (!gpio_is_valid(spi_dev->cs_gpio))
	{
		printk("%d is not a valid gpio\n", spi_dev->cs_gpio);
		return -EINVAL;
	}

	return gpio_direction_output(spi_dev->cs_gpio, !(spi_dev->mode & SPI_CS_HIGH));
}

static int spi_virtual_transfer(struct spi_device *spi, struct spi_message *mesg)
{
	//SPI框架在调用此函数时使用spi_master中的bus_lock_spinlock自旋锁进行了加锁，所以此函数不能休眠
	unsigned long flags;
	struct virtual_spi_master *virtual_master;
	struct spi_master *master;

	master = spi->master;
	virtual_master = spi_master_get_devdata(master);

	//获取自旋锁
	spin_lock_irqsave(&master->queue_lock, flags);

	//把消息放入队列
	mesg->actual_length = 0;
	mesg->status = -EINPROGRESS;
	list_add_tail(&mesg->queue, &master->queue);

	//完成后解锁
	spin_unlock_irqrestore(&master->queue_lock, flags);

	//启动工作队列
	schedule_work(&virtual_master->work_queue);

	return 0;
}

static int spi_virtual_probe(struct platform_device *pdev)
{
	int result;
	int i, num_cs, cs_gpio;
	struct spi_master *master;
	struct virtual_spi_master *virtual_master;

	printk("%s\r\n", __FUNCTION__);
	//分配 spi_master 和 virtual_spi_master
	master = spi_alloc_master(&pdev->dev, sizeof(struct virtual_spi_master));
	if(!master)
	{
		printk("alloc spi_master fail\n");
		return -ENOMEM;
	}

	//获取分配的 virtual_spi_master
	virtual_master = spi_master_get_devdata(master);

	//初始化 virtual_spi_master
	virtual_master->spi_master = master;
	INIT_WORK(&virtual_master->work_queue, spi_virtual_work);

	//初始化 spi_master
	virtual_master->spi_master->setup = spi_virtual_setup;
	virtual_master->spi_master->transfer = spi_virtual_transfer;
	virtual_master->spi_master->dev.of_node = pdev->dev.of_node;
	virtual_master->spi_master->bus_num = pdev->id;
	virtual_master->spi_master->max_speed_hz = 1000000000;
	virtual_master->spi_master->min_speed_hz = 1000;
	virtual_master->spi_master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE;

	/* SPI驱动框架仅仅是从设备树中获取片选引脚并记录，未进行request引脚 */
	num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios");
	for (i = 0; i < num_cs; i++)
	{
		cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
		if (cs_gpio == -EPROBE_DEFER)
		{
			/* 释放前面分配的 spi_master，它通过于 spi_master 绑定的 dev 来实现
			* 其调用流程如下：
			* 	spi_master_put
			* 		spi_controller_put
			* 			put_device
			* 				kobject_put
			* 					kref_put
			* 						kobject_release
			* 							kobject_cleanup
			* 								t->release，这里应该是device_initialize为其注册的device_ktype中的device_release
			* 									dev->class->dev_release，这里应该是分配spi_master时为dev.class绑定的spi_master_class中的spi_controller_release
			*/
			spi_master_put(virtual_master->spi_master);
			return -EPROBE_DEFER;
		}

		if(gpio_is_valid(cs_gpio))
		{
			result = devm_gpio_request(&pdev->dev, cs_gpio, "virtual_spi_cs");
			if(result < 0)
			{
				spi_master_put(virtual_master->spi_master);
				printk("can't get CS gpio %i\n", cs_gpio);
				return result;
			}
		}
	}

	//注册 spi_master
	result = spi_register_master(virtual_master->spi_master);
	if (result < 0) {
		printk("register spi_master fail\n");
		spi_master_put(virtual_master->spi_master);
		return result;
	}

	//设置平台设备的驱动私有数据
	pdev->dev.driver_data = (void*)virtual_master;

	return 0;
}

static int spi_virtual_remove(struct platform_device *pdev)
{
	struct virtual_spi_master *virtual_master;

	printk("%s\r\n", __FUNCTION__);
	//提取平台设备的驱动私有数据
	virtual_master = (struct virtual_spi_master*)pdev->dev.driver_data;
	//注销spi_master
	spi_unregister_master(virtual_master->spi_master);
	return 0;
}

static const struct of_device_id spi_virtual_of_match[] = {
	{.compatible = "atk,virtual_spi_master"},
	{ /* Sentinel */ }
};
static struct platform_driver spi_virtual_driver = {
	.probe = spi_virtual_probe,
	.remove = spi_virtual_remove,
	.driver = {
		.name = "virtual_spi",
		.of_match_table = spi_virtual_of_match,
	},
};

static int virtual_master_init(void)
{
	printk("%s\r\n", __FUNCTION__);
	return platform_driver_register(&spi_virtual_driver);
}

static void virtual_master_exit(void)
{
	printk("%s\r\n", __FUNCTION__);
	platform_driver_unregister(&spi_virtual_driver);
}

module_init(virtual_master_init);
module_exit(virtual_master_exit);

MODULE_DESCRIPTION("virtual SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lf");
